package com.lz.ub.core

import android.os.Handler
import android.os.Looper
import android.os.Message
import com.lz.ub.UBCCallback
import com.lz.ub.UBCCallbackExecute
import com.lz.ub.UBCDevice
import com.lz.ub.UBCScanCallback

/**
 * @author You
 * USB Command回调线程切换器 实现类
 */
class UBCCallbackHandler(
    override val callback: UBCCallback,
    override val scanCallback: UBCScanCallback
) : Handler(Looper.getMainLooper()), UBCCallbackExecute {

    companion object {

        //连接
        const val MSG_CONNECTED = 1

        //断开
        const val MSG_DISCONNECTED = 2

        //读取消息
        const val MSG_READ = 3

        //读取16进制
        const val MSG_READ_HEX = 4

        //扫描结果
        const val MSG_SCAN_RESULT = 5
    }

    override fun handleMessage(msg: Message) {
        when (msg.what) {
            MSG_CONNECTED -> callback.onConnected(msg.obj as UBCDevice, msg.arg1 == 1)
            MSG_DISCONNECTED -> callback.onDisconnected(msg.obj as UBCDevice, msg.arg1 == 1)
            MSG_READ -> {
                val msgData = msg.obj as MsgData
                callback.onRead(msgData.device!!, msgData.data!!, msg.arg1 == 1)
                msgData.recycle()
            }
            MSG_READ_HEX -> {
                val msgData = msg.obj as MsgData
                callback.onReadHex(msgData.device!!, msgData.bytes!!, msgData.start, msgData.size, msg.arg1 == 1)
                msgData.recycle()
            }
            MSG_SCAN_RESULT -> scanCallback.onScanResult(msg.obj as UBCScanResult)
        }
    }

    override fun sendConnected(device: UBCDevice, isAssist: Boolean) {
        sendMessage(obtainMessage(MSG_CONNECTED, if (isAssist) 1 else 0, 0, device))
    }

    override fun sendDisconnected(device: UBCDevice, isAssist: Boolean) {
        sendMessage(obtainMessage(MSG_DISCONNECTED, if (isAssist) 1 else 0, 0, device))
    }

    override fun sendReceived(device: UBCDevice, data: String, isAssist: Boolean) {
        sendMessage(obtainMessage(MSG_READ, if (isAssist) 1 else 0, 0, MsgData.obtain(device, data)))
    }

    override fun sendReceivedHex(device: UBCDevice, bytes: ByteArray, start: Int, size: Int, isAssist: Boolean) {
        sendMessage(obtainMessage(MSG_READ_HEX, if (isAssist) 1 else 0, 0, MsgData.obtain(device, bytes, start, size)))
    }

    override fun sendScan(result: UBCScanResult) {
        sendMessage(obtainMessage(MSG_SCAN_RESULT, result))
    }

    /**
     * 线程调度时, 避免大量创建Runnable Post的消息池
     */
    private class MsgData {

        companion object {
            //最大5个缓存池大小
            private const val MAX_POOL_SIZE = 5

            //异步锁对象
            private val sPoolSync = Any()

            private var sPool: MsgData? = null

            //当前池大小
            private var sPoolSize: Int = 0

            private fun obtain(): MsgData {
                synchronized(sPoolSync) {
                    if (sPool != null) {
                        val m = sPool
                        sPool = m!!.next
                        m.next = null
                        sPoolSize--
                        return m
                    }
                }
                return MsgData()
            }

            fun obtain(device: UBCDevice, bytes: ByteArray, start: Int, size: Int): MsgData = obtain().also {
                it.device = device; it.bytes = bytes; it.start = start; it.size = size
            }

            fun obtain(device: UBCDevice, data: String): MsgData = obtain().also {
                it.device = device; it.data = data
            }
        }

        //池里下一引用
        var next: MsgData? = null

        //相关属性值
        var device: UBCDevice? = null
        var bytes: ByteArray? = null
        var data: String? = null
        var start: Int = 0
        var size: Int = 0

        //回收到池中
        fun recycle() {
            device = null
            bytes = null
            data = null
            start = 0
            size = 0
            synchronized(sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool
                    sPool = this
                    sPoolSize++
                }
            }
        }
    }
}